﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using HtmlAgilityPack;
using System.Drawing;

namespace Yah.Parser
{
    /// <summary>
    ///Hoai Nam
    ///input link trang tin tức
    ///output xpath để lấy ra tiêu đề và nội dung tin trong trang đó
    ///sử dụng thư viện nguồn mở http://htmlagilitypack.codeplex.com/ để load HTMLDocument
    ///sử dụng dự án nguồn mở http://www.codeproject.com/Articles/35978/Reading-Image-Headers-to-Get-Width-and-Height để đọc header của ảnh 
    ///.net ver 4.0
    ///Throw Exeption nếu gặp lỗi !!!
    /// </summary>
    public class ContentExtractor
    {
        public static string UserAgent = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)";

        //Google bot

        //private static string _userAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)";//IE 8
        public HtmlDocument HtmlDocument = null;
        private HtmlNode _titleNode;
        private string _titleText; //title node sẽ bị xóa trong quá trình lấy content nên cần lưu title vào text
        private string _titleXpath;
        private bool _runed;
        private readonly string _url;
        private readonly ImageProcess _imageProcess;

        public ContentExtractor(string url)
        {
            if (!url.Contains("://")) url = "http://" + url;
            _url = url;
            try
            {
                //tải trang web về và load HtmlDocument
                HtmlDocument = HtmlParser.GetHtmlDoc(url, out _url, out _allContent);
            }
            catch
            {
                throw new Exception("Quá trình tải trang web về bị lỗi, lỗi này có thể do kết nối internet có vấn đề");
            }
            _preProcessHtmlDocument();
            _imageProcess = new ImageProcess(_url, HtmlDocument);
        }

        /// <summary>
        /// Hàm tiền xử lý htmldocument loại bỏ nhưng thành phần không cần thiết như là script, các thẻ comment
        /// Loại bỏ thuộc tính của các thẻ font
        /// </summary>
        private void _preProcessHtmlDocument()
        {
            HtmlNodeCollection lst = HtmlDocument.DocumentNode.SelectNodes("//script");
            if (lst != null)
            {
                foreach (HtmlNode row in lst)
                {
                    row.Remove();
                }
            }
            HtmlNodeCollection lst2 = HtmlDocument.DocumentNode.SelectNodes("//comment()");
            if (lst2 != null)
            {
                foreach (HtmlNode row in lst2)
                {
                    row.Remove();
                }
            }
            HtmlNodeCollection lst3 = HtmlDocument.DocumentNode.SelectNodes("//font");
            if (lst3 != null)
            {
                foreach (HtmlNode row in lst3)
                {
                    row.Attributes.RemoveAll();
                }
            }
            HtmlNodeCollection lst4 = HtmlDocument.DocumentNode.SelectNodes("//iframe");
            if (lst4 != null)
            {
                foreach (HtmlNode row in lst4)
                {
                    row.Remove();
                }
            }
           // HtmlDocument.DocumentNode.InnerHtml = HtmlDocument.DocumentNode.InnerHtml.Replace("\r", "").Replace("\n", "").Replace("\t", "");
        }

        #region title function

        /// <summary>
        /// Tính độ tương đồng về từ khóa giữa 2 chuỗi text
        /// </summary>
        /// <param name="title"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        private int _tinhDoTuongDong(string title, string input)
        {
            var kq = 0;
            var srrInput = input.Split(' ');
            for (int i = 0; i < srrInput.Length; ++i)
            {
                if (srrInput[i].Trim() != "")
                {
                    if (!" !@#$%^&*()_+-={}[]|\\:;\"\'<,>.?/".Contains(srrInput[i]))
                    {
                        if (title.Contains(srrInput[i].Trim()))
                        {
                            kq += 1;
                        }
                    }
                }
            }

            //trường hợp title chứa toàn bộ nội dung của thẻ này thì nhân 1.5 lần kết quả
            if (title.Contains(input.Trim()))
            {
                kq = (int) (kq*1.5);
            }
            return kq;
        }

        /// <summary>
        /// Tìm thẻ html chứa title của bài viết và lưu vào _titleNode
        /// Nếu tìm thấy thì trả về true và ngược lại
        /// </summary>
        /// <returns></returns>
        private bool _getTitleNode()
        {
            _runed = true;
            //tim den the co chua title
            var title = HtmlDocument.DocumentNode.ChildNodes["html"].ChildNodes["head"].ChildNodes["title"].InnerText;
            var lenTitle = title.Length;
            //tim phan noi dung trong the h 
            double doTuongDongMax = 0;

            HtmlNode elementDoTuongDongMax = null;
            var lstNode = HtmlDocument.DocumentNode.ChildNodes["html"].ChildNodes["body"].Descendants();
            var lis = new List<String>();
            foreach (var oneNode in lstNode)
            {
                if (oneNode.InnerText.Trim().Length <= lenTitle && oneNode.InnerText.Trim().Length > 10)
                {
                    //tinh diem cho tag name
                    double scoreForTagName = 0;
                    switch (oneNode.Name.ToUpper())
                    {
                        case "H1":
                            scoreForTagName = 8;
                            break;
                        case "H2":
                            scoreForTagName = 7;
                            break;
                        case "H3":
                            scoreForTagName = 6;
                            break;
                        case "H4":
                            scoreForTagName = 5;
                            break;
                        case "H5":
                            scoreForTagName = 4;
                            break;
                        case "H6":
                            scoreForTagName = 3;
                            break;
                        case "B":
                            scoreForTagName = 0.5;
                            break;
                        case "STRONG":
                            scoreForTagName = 0.5;
                            break;
                        default:
                            scoreForTagName = 0;
                            break;
                    }
                    //do dai khong duoc lon hon do dai tieu de
                    //trung hop nay bo qua diem ve do dai 
                    double scoreForLen = 0;
                    if (oneNode.InnerText.Trim().Length <= lenTitle)
                    {
                        scoreForLen = 0.5;
                    }
                    //tinh diem su ton tai cua text dang xet nam trong tieu de, neu doan text dang xet co nam trong tieu de thi cong them diem 
                    double scoreForContain = 0;
                    if (title.Trim().ToLower().Contains(oneNode.InnerText.ToLower().Trim()))
                    {
                        scoreForContain = 1;
                    }

                    if (scoreForLen > 0)
                    {
                        //kiem tra do tuong doi voi title
                        var doTuongDongTmp = (scoreForTagName + scoreForLen + scoreForContain +
                                              _tinhDoTuongDong(title.Trim().ToLower(),
                                                               oneNode.InnerText.Trim().ToLower()));

                        if (doTuongDongMax < doTuongDongTmp)
                        {
                            doTuongDongMax = doTuongDongTmp;
                            elementDoTuongDongMax = oneNode;
                            lis.Add(doTuongDongMax.ToString() + "     " + doTuongDongTmp.ToString() + "        " +
                                    oneNode.Name + "   " + oneNode.InnerText);
                        }
                    }
                }
            }
            lis.Sort();
            G.Log(lis.Count.ToString(CultureInfo.InvariantCulture));
            if (doTuongDongMax > 1)
            {
                //tim duoc element co do tuong dong max - coi day la title - dung vi tri nay de lay noi dung
                _titleNode = elementDoTuongDongMax;
                if (_titleNode != null)
                {
                    _titleText = HttpUtility.HtmlDecode(_titleNode.InnerText.Trim());
                    _titleXpath = _titleNode.XPath;
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// Lấy ra nội dung text của tiêu đề
        /// Trả về null nếu không lấy được tiêu đề hoặc là trang đang xét không phải trang chứa nội dung tin
        /// </summary>
        /// <returns></returns>
        public string GetTitle()
        {
            if (_titleText == null && _runed == false)
            {
                _getTitleNode();
            }
            if (_titleText != null)
            {
                return _titleText;
            }
            return null;
        }

        /// <summary>
        /// Lấy ra xpath trỏ đến node chứa tiêu đề
        /// Trả về null nếu không lấy được tiêu đề hoặc là trang đang xét không phải trang chứa nội dung tin
        /// </summary>
        /// <returns></returns>
        public string GetTitleXpath()
        {
            if (_titleText == null && _runed == false)
            {
                _getTitleNode();
            }
            if (_titleText != null)
            {
                return _titleXpath;
            }
            return null;
        }
        private int dotuongdong(HtmlNode nodeHtml)
        {
            var lis = (from childNode in nodeHtml.ChildNodes where childNode.InnerText.Trim().Length > 120 select childNode.InnerText.Trim().Length).ToList();
            int res = 0;
            for (var i = 1; i < lis.Count; ++i)
            {
                var tmp = lis[i - 1]*0.3;
                if (Math.Abs(lis[i - 1] - lis[i]) > tmp)
                {
                    res++;
                }
            }
                return res;
        }

        #endregion

        #region content function

        private string _contentHtml;
        private string _contentText;
        private string _contentXpath;
        private HtmlNode _contentNode;
        private readonly string _allContent;

        /// <summary>
        /// Lấy ra text chứa nội dung 
        /// </summary>
        /// <returns></returns>
        public string GetContentText()
        {
            G.Log("getContentText >> START");
            if (_contentText != null) return _contentText;
            if (_titleText == null && _runed == false) _getTitleNode();
            if (_titleText == null) return null;

            #region BƯỚC 1

            DataAttri scoreOfNode;
            G.Log("getContentText: BƯỚC 1");
            var nowNode1 = _titleNode;
            do
            {
                if (nowNode1.Name.ToLower() == "body")
                {
                    break;
                }
                nowNode1 = nowNode1.ParentNode;
                scoreOfNode = _calPoint(nowNode1);
            } while (!(scoreOfNode.TextLenght > 1000 || scoreOfNode.ImageHeight >= 600));

            //nowNode tìm được chính là Node chứa nội dung và tiêu đề của bài viết

            #endregion

            //BƯỚC 2: Tìm đến node parent trực tiếp của phần nội dung

            #region BƯỚC 2

            G.Log("getContentText: BƯỚC 2");
            var nowNode = GetMaxScoreNode(nowNode1);

            #endregion

            //BƯỚC 3: loại bỏ những node thừa ở cuối -> tính điểm xem đâu là node cuối cùng của bài viết -> xét từ dưới lên

            #region BƯỚC 3

            //công thức tính điểm: 
            //node text >> -intertext.lenght / 18 (trừ vào node trước nó)
            //node chứa input >> +numberOfInput (cộng cho node trước nó)
            //node chứa smallimage >> +numberOfSmallImage (cộng cho node trước nó) 
            //node chứa quá ít text < 20 >> cộng cho chính node này 1 điểm
            //node chưa toàn link >> +numberOfLink (cộng cho node trước nó)
            //ko phải node chưa toàn link và node chứa nhiều text >> - độ dài text /120 (cộng cho node trước nó)
            //node chứa ảnh to >> -chieu` cao cua node/18 (cộng cho node trước nó)
            //lấy node có điểm số cao nhất từ trên xuống đây chính là node cuối cùng của nội dung (cộng cho node trước nó)
            G.Log("getContentText: BƯỚC 3 loại bỏ những node thừa ở cuối");
            int nowNodeScore;
            HtmlNode nowChildNode;
            DataAttri nowChildNodeData;
            var lstChild = nowNode.ChildNodes;
            var maxScoreChildNode = lstChild[lstChild.Count - 1];
            var maxScoreChildNodeScore = 0;
            var preNodeScore = 1;

            //cộng 1 điểm cho node cuối cùng của nowNode node cuối này có khả năng là node kết thục của content
            for (var i = lstChild.Count - 1; i > -1; --i)
            {
                //renew
                nowNodeScore = preNodeScore;
                preNodeScore = 0;
                nowChildNode = lstChild[i];
                if (nowChildNode.Name.ToLower() == "#text")
                {
                    //text dài
                    preNodeScore -=
                        nowChildNode.InnerText.Replace("\r", "").Replace("\n", "").Replace("\t", "").Trim().Length/18;
                }
                else
                {
                    //thực hiện công thức tính điểm
                    nowChildNodeData = _calPoint(nowChildNode);
                    //input
                    preNodeScore += nowChildNodeData.NumberOfInput;
                    //ảnh nhỏ
                    preNodeScore += nowChildNodeData.NumberOfSmallImage;
                    //text ngắn
                    if (nowChildNodeData.TextLenght < 50)
                    {
                        nowNodeScore++;
                    }
                    //list link
                    var tmpNumOfLink = _isListOfLink(nowChildNode);
                    if (tmpNumOfLink > 0)
                    {
                        preNodeScore += tmpNumOfLink;
                    }
                        //node nhiều text
                    else if (nowChildNodeData.TextLenght > 50)
                    {
                        preNodeScore -= (nowChildNodeData.TextLenght + 120)/120;
                    }
                    //ảnh to
                    preNodeScore -= nowChildNodeData.ImageHeight;
                }
                //G.Log("\n" + nowChildNode.OuterHtml + "\nScore:" + nowNodeScore.ToString(CultureInfo.InvariantCulture));
                //thực hiện kiểm tra tìm node có điểm cao nhất (2 node có điểm bằng nhau thì lấy node phia trên) 
                if (nowNodeScore >= maxScoreChildNodeScore)
                {
                    maxScoreChildNodeScore = nowNodeScore;
                    maxScoreChildNode = nowChildNode;
                }
                //cộng dồn điểm của node hiện tại vào node sau nó
                preNodeScore += nowNodeScore;
            }
            //maxScoreChildNode chính là node cuối cùng của nội dung bài viết
            //remote các node nằm sau nó


            while (maxScoreChildNode.NextSibling != null)
            {
                maxScoreChildNode.NextSibling.Remove();
            }

            // G.Log(nowNode.OuterHtml + nowNode.ChildNodes.Count.ToString(CultureInfo.InvariantCulture));
            // G.Log("\nEndNode\n" + maxScoreChildNode.OuterHtml + "\nScore:" +
            //       maxScoreChildNodeScore.ToString(CultureInfo.InvariantCulture));

            #endregion

            //BƯỚC 4 loại bỏ những node thừa ở đầu

            #region BƯỚC 4

            //xóa bỏ node chứa tiêu đề

            _titleNode.Remove();
            //công thức tính điểm: 
            //node text >> -intertext.lenght / 18 (trừ vào node sau nó)
            //node chứa input >> +numberOfInput (cộng cho node sau nó)
            //node chứa smallimage >> +numberOfSmallImage (cộng cho node sau nó) 
            //node là node h1 h2 h3 h4 h5 h6>> trừ vào nó 2 điểm và cộng vào node sau nó 2 điểm
            //node chưa toàn link >> +numberOfLink (cộng cho node sau nó)
            //ko phải node chưa toàn link và node chứa nhiều text >> - độ dài text /120 (cộng cho node sau nó)
            //node chứa ảnh to >> -chieu` cao cua node/18 (cộng cho node sau nó)
            //lấy node có điểm số cao nhất dưới lên đây chính là node cuối cùng của nội dung 
            G.Log("getContentText: BƯỚC 4 loại bỏ những node thừa ở đầu");
            lstChild = nowNode.ChildNodes;
            maxScoreChildNode = lstChild[0];
            maxScoreChildNodeScore = 0;
            
            var nextNodeScore = 1;
            for (var i = 0; i < lstChild.Count; ++i)
            {
                //renew
                nowNodeScore = nextNodeScore;
                nextNodeScore = 0;
                nowChildNode = lstChild[i];
                if (nowChildNode.Name.ToLower() == "#text")
                {
                    //text dài
                    nextNodeScore -=
                        nowChildNode.InnerText.Replace("\r", "").Replace("\n", "").Replace("\t", "").Trim().Length/18;
                }
                else
                {
                    //thực hiện công thức tính điểm
                    nowChildNodeData = _calPoint(nowChildNode);
                    //input
                    nextNodeScore += nowChildNodeData.NumberOfInput;
                    //ảnh nhỏ
                    nextNodeScore += nowChildNodeData.NumberOfSmallImage;
                    var tmpNumOfLink = _isListOfLink(nowChildNode);
                    //cac the h
                    if ("h1$h2$h3$h4$h5$h6$".Contains(nowChildNode.Name.ToLower() + "$"))
                    {
                        nowNodeScore -= 2;
                        nextNodeScore += 2;
                    } //list link
                    else if (tmpNumOfLink > 0)
                    {
                        nextNodeScore += tmpNumOfLink;
                    }
                        //node nhiều text
                    else if (nowChildNodeData.TextLenght > 50)
                    {
                        nextNodeScore -= ((nowChildNodeData.TextLenght + 120)/120);
                    }
                    //ảnh to
                    nextNodeScore -= nowChildNodeData.ImageHeight;
                }
                //   G.Log("\n" + nowChildNode.OuterHtml + "\nScore:" + nowNodeScore.ToString(CultureInfo.InvariantCulture));
                //thực hiện kiểm tra tìm node có điểm cao nhất (2 node có điểm bằng nhau thì lấy node phia dưới) 
                if (nowNodeScore >= maxScoreChildNodeScore)
                {
                    maxScoreChildNodeScore = nowNodeScore;
                    maxScoreChildNode = nowChildNode;
                }
                //cộng dồn điểm vào node trước nó
                nextNodeScore += nowNodeScore;
            }
            //maxScoreChildNode chính là node đầu tiên của nội dung bài viết
            //remote các node nằm trước nó


            while (maxScoreChildNode.PreviousSibling != null)
            {
                maxScoreChildNode.PreviousSibling.Remove();
            }

            #endregion

            //trả về kết quả
            _contentHtml = nowNode.InnerHtml;
            _contentText = HttpUtility.HtmlDecode(nowNode.InnerText);
            _contentXpath = nowNode.XPath;
            _contentNode = nowNode;
            G.Log("getContentText >> FINISH");
            return _contentText;
        }

        /// <summary>
        /// Kiểm trả xem đấy có phải là 1 danh sách gồm toàn link hay không (nếu có nhiều link mà chỉ có 1 text node với độ dài không quá 20 thì cũng xếp vào loại link list)
        /// trả về số link chứ trong nó nếu chứa toàn link, nếu không thì trả về -1 nghĩa là có thể có link nhưng node này còn chứa cả text
        /// </summary>
        /// <param name="inp"></param>
        /// <returns></returns>
        private int _isListOfLink(HtmlNode inp)
        {
            var numOfANode = 0;
            var numOfTextNode = 0;
            var st = new Stack<HtmlNode>();
            st.Push(inp);
            while (st.Count > 0)
            {
                var tmp = st.Pop();
                var lst = tmp.ChildNodes;
                if (lst != null)
                {
                    foreach (var row in lst)
                    {
                        if (row.Name.ToLower() == "a")
                        {
                            numOfANode++;
                        }
                        else
                        {
                            if (row.Name.ToLower() == "#text")
                            {
                                int tmpLen =
                                    row.InnerText.Replace("\r", "").Replace("\n", "").Replace("\t", "").Trim().Length;
                                if (tmpLen > 100)
                                {
                                    numOfTextNode++;
                                }
                            }
                            else
                            {
                                st.Push(row); //đưa vào stack để tiếp tục xử lý các node con
                            }
                        }
                    }
                }
            }
            if (numOfTextNode <= 1)
            {
                return numOfANode;
            }
            return -numOfANode;
        }

        /// <summary>
        /// Trả về mã HTML chứa content
        /// </summary>
        /// <returns></returns>
        public string GetContentHTML()
        {
            if (_contentHtml != null) return _contentHtml;
            GetContentText();
            return _contentHtml;
        }

        /// <summary>
        /// Trả về node chưa content
        /// </summary>
        /// <returns>HtmlNode</returns>
        public HtmlNode GetContentNode()
        {
            if (_contentNode == null)
            {
                GetContentText();
            }
            return _contentNode;
        }

        /// <summary>
        /// Trả về chuỗi Xpath trỏ đến content
        /// </summary>
        /// <returns></returns>
        public string GetContentXpath()
        {
            if (_contentXpath != null) return _contentXpath;
            GetContentText();
            return _contentXpath;
        }

        /// <summary>
        /// những ảnh có kich thước nhỏ hơn hoặc bằng gia trị này được coi là ảnh nhỏ
        /// </summary>
        private Size _sizeOfSmallImage = new Size(700, 160);

        public class DataAttri
        {
            public int TextLenght;
            public int ImageHeight;
            public int NumberOfLongText;
            public int NumberOfDirectLongText;
            public int NumberOfDirectBigImage;
            public int NumberOfSmallImage;
            public int NumberOfInput;
            public int NumberParentOfLongText;
            public int NumberParentOfBigImage;
            public int NumberOfLink;

            public String GetVector()
            {
                var resVector = "";
                resVector += "1:" + TextLenght.ToString(CultureInfo.InvariantCulture);
                resVector += " 2:" + ImageHeight.ToString(CultureInfo.InvariantCulture);
                resVector += " 3:" + NumberOfLongText.ToString(CultureInfo.InvariantCulture);
                resVector += " 4:" + NumberOfDirectLongText.ToString(CultureInfo.InvariantCulture);
                resVector += " 5:" + NumberOfDirectBigImage.ToString(CultureInfo.InvariantCulture);
                resVector += " 6:" + NumberOfSmallImage.ToString(CultureInfo.InvariantCulture);
                resVector += " 7:" + NumberOfInput.ToString(CultureInfo.InvariantCulture);
                resVector += " 8:" + NumberParentOfLongText.ToString(CultureInfo.InvariantCulture);
                resVector += " 9:" + NumberParentOfBigImage.ToString(CultureInfo.InvariantCulture);
                resVector += " 10:" + NumberOfLink.ToString(CultureInfo.InvariantCulture);
                return resVector;
            }

            public DataAttri()
            {
                TextLenght = 0;
                ImageHeight = 0;
                NumberOfLongText = 0;
                NumberOfDirectLongText = 0;
                NumberOfDirectBigImage = 0;
                NumberOfSmallImage = 0;
                NumberOfInput = 0;
                NumberParentOfLongText = 0;
                NumberParentOfBigImage = 0;
                NumberOfLink = 0;
            }

            public void SetDataAttri(String vectorDataArrti)
            {
                var arrti = vectorDataArrti.Split(' ');
                TextLenght = Convert.ToInt32(arrti[0].Substring(2));
                ImageHeight = Convert.ToInt32(arrti[1].Substring(2));
                NumberOfLongText = Convert.ToInt32(arrti[2].Substring(2));
                NumberOfDirectLongText = Convert.ToInt32(arrti[3].Substring(2));
                NumberOfDirectBigImage = Convert.ToInt32(arrti[4].Substring(2));
                NumberOfSmallImage = Convert.ToInt32(arrti[5].Substring(2));
                NumberOfInput = Convert.ToInt32(arrti[6].Substring(2));
                NumberParentOfLongText = Convert.ToInt32(arrti[7].Substring(2));
                NumberParentOfBigImage = Convert.ToInt32(arrti[8].Substring(2));
                NumberOfLink = Convert.ToInt32(arrti[9].Substring(3));
            }

            public int GetScore()
            {
                var res = TextLenght/1000
                          + ImageHeight
                          + NumberOfLongText*200
                          + NumberOfDirectLongText*60
                          + NumberOfDirectBigImage*60
                          + NumberParentOfLongText*60
                          + NumberParentOfBigImage*60
                          - NumberOfInput*100
                          - NumberOfSmallImage*100
                          - NumberOfLink*5;
                return res;
            }
        }


        private HtmlNode GetMaxScoreNode(HtmlNode htmlNode)
        {
            var resNode = htmlNode;
            var maxScore = _calPoint(htmlNode);
            var lis = new List<String> {maxScore.GetScore() + " " + maxScore.GetVector() + "\n" + htmlNode.OuterHtml};
            foreach (var node in htmlNode.Descendants())
            {
                if (!@"<br><#text><img>".Contains("<" + node.Name.ToLower() +">"))
                {
                    var tmpScore = _calPoint(node);
                    lis.Add(maxScore.GetScore() + " <-> " + tmpScore.GetScore() + "\n "
                            + tmpScore.GetVector()
                            +" 11:"+dotuongdong(node)
                            + "\n   " + node.InnerHtml);
                    if (maxScore.GetScore() == tmpScore.GetScore())
                    {
                        if (node.ParentNode == resNode)
                        {
                            resNode = node;
                        }
                    }
                    else if (maxScore.GetScore() < tmpScore.GetScore())
                    {
                        resNode = node;
                        maxScore = tmpScore;
                    }
                }
            }
            G.Log(lis.Count.ToString(CultureInfo.InvariantCulture));
            htmlNode = resNode;
            return resNode;
        }


        /// <summary>
        /// Hàm đệ quy chấm điểm cây dom mà nut gốc là HtmlNode được chuyền vào
        /// </summary>
        /// <param name="parent"></param>
        /// <returns></returns>
        private DataAttri _calPoint(HtmlNode parent)
        {
            var res = new DataAttri();
            //kiểm tra nếu thẻ này đã được chấm điểm thì load dữ liệu điểm và return luôn
            if (parent.Attributes["vectorArrti"] != null)
            {
                res.SetDataAttri(parent.Attributes["vectorArrti"].Value);
                return res;
            }
            //kiểm tra xem thẻ này có dudocj hiển thị không
            var styleAtt = parent.Attributes["style"];
            if (styleAtt != null && styleAtt.Value.Replace(" ", "").ToLower().Contains("display:none"))
            {
                parent.InnerHtml = "";
                parent.Attributes.Add("vectorArrti", res.GetVector());
                return res;
            }
            //chưa được chấm điểm thì bắt đầu xử lý chấm điểm
            foreach (var row in parent.ChildNodes)
            {
                if (row.Name.ToLower() == "#text")
                {
                    //nếu là thẻ text thì cộng ngày vào độ dài text
                    int tmpLenText = row.InnerText.Replace("\r", "").Replace("\n", "").Replace("\t", "").Trim().Length;
                    res.TextLenght += tmpLenText;
                    if (tmpLenText > 120)
                    {
                        res.NumberOfLongText++;
                        res.NumberOfDirectLongText++;
                    }
                }
                else
                {
                    if (row.Name.ToLower() == "img")
                    {
                        //nếu là thẻ ảnh thì kiểm tra xem là ảnh lớn hay ảnh bé để cộng vào phần tương ứng
                        Size tmp = _imageProcess.GetSizeOfImgNode(row);
                        if (tmp.Width < _sizeOfSmallImage.Width && tmp.Height < _sizeOfSmallImage.Height)
                        {
                            //small image
                            res.NumberOfSmallImage++;
                        }
                        else
                        {
                            res.ImageHeight += 300;
                            res.NumberOfDirectBigImage++;
                        }
                        //set thuộc tinh src của ảnh thành real url để có thể load ảnh ở mọi nơi
                        row.Attributes["src"].Value = _imageProcess.GetUrlFormSrc(row.Attributes["src"].Value);
                    }
                    else
                    {
                        if (row.Name.ToLower() == "input" || row.Name.ToLower() == "textarea")
                        {
                            res.NumberOfInput++;
                        }
                        else
                        {
                            if (row.InnerHtml.Trim().Length > 0)
                            {
                                //nếu không thuộc các trường hợp trên thì phải kiểm tra loai bỏ 1 số TH như thẻ br khong co text chua ben trong
                                if (row.Name.ToLower() == "a")
                                {
                                    res.NumberOfLink++;
                                }
                                var tmp = _calPoint(row);
                                res.TextLenght += tmp.TextLenght;
                                res.ImageHeight += tmp.ImageHeight;
                                res.NumberOfSmallImage += tmp.NumberOfSmallImage;
                                res.NumberOfInput += tmp.NumberOfInput;
                                res.NumberOfLongText += tmp.NumberOfLongText;
                                res.NumberOfLink += tmp.NumberOfLink;
                                if (tmp.NumberOfDirectBigImage > 0)
                                {
                                    res.NumberParentOfBigImage++;
                                }
                                if (tmp.NumberOfDirectLongText > 0)
                                {
                                    res.NumberParentOfLongText++;
                                }
                            }
                        }
                    }
                }
            }
            //Gán các dữ liệu này vào thuộc tính của thẻ
            parent.Attributes.Add("vectorArrti", res.GetVector());
            return res;
        }

        #endregion

        #region common

        public string GetAllContent()
        {
            return _allContent;
        }

        public string GetUrl()
        {
            return _url;
        }

        public DataAttri GetDataArrti(HtmlNode htmlNode)
        {
            return _calPoint(htmlNode);
        }

        #endregion
    }
}